There exist high availability computer applications that run on very reliable computer systems for many important applications. These systems and programs typically run 24 hours a day, 7 days a week, and any interruption to processing can have serious repercussions in terms of customer service and, in some situations, safety. For example, the advent of electronic commerce over the Internet and World Wide Web requires that e-commerce websites always be available for processing transactions. Other examples include credit card transaction processing applications, air traffic control applications, etc.
As software for such mission critical applications is enhanced “off-line” on development environments, it becomes necessary to deploy or refresh such enhanced software “online” into the production environment. Previous ways of deploying such enhancements has required saving state data, shutting down or otherwise impairing the availability of the critical application, installing the new software, restarting the application or otherwise making it fully available, and then restoring the previous state of the software. At this point, the application would be running the enhanced code with the existing data.
By shutting down the system or introducing another performance impacting event, such as a manual quiescing of the system, service is disrupted. To avoid service disruption, software updates are often delayed as long as possible, with the risk of jeopardizing security and safety. Therefore, there exists a need to apply changes (enhancements and/or maintenance) to one or more modules of software within an actively-running system without requiring a shutdown or interruption of that system. Furthermore, there exists a need to add or delete such modules within an actively-running system.
As a growing class of mission critical applications is written in statically-typed class-based object-oriented programming languages, there is a need to address the specific challenges of dynamically updating classes within individual modules of such applications.
When updating modules, written in a statically-typed class-based object-oriented programming language, on a running system, the updating would need to preserve state information from previous instances of the changed classes and to provide this information to the new instances of these classes. Furthermore, the need exists to ensure that the updating of a set of classes is done atomically, as it otherwise can cause binary incompatibilities, due to changes in the type of the former version and the new version of a class, which will cause runtime failures and bring the whole system to a stop.
The widely accepted statically-typed class-based object-oriented programming language Java™ does have some support for dynamic redefinition of classes, through an implementation of Dmitriev's proposed class reloading facilities [5]. A redefinition may change the programming code of method bodies, the constant pool and attributes. However, a class redefinition must not add, remove or rename fields or methods, change the signatures of methods, change modifiers, or change the inheritance hierarchy. These restrictions are imposed to avoid binary incompatibility issues between subsequent versions of a class. In practice these restrictions render the current class redefinition capability in Java™ unsuitable for supporting most dynamic updates required for large and long-lived mission critical applications.
In [6] Malabarba et al. disclose the method Dynamic Java Classes, that based on a modified Java Virtual Machine with a new dynamic class loader, allows any change to a Java class as long as no other classes, currently present in the actively running software, depend on the part of the class being changed. By imposing this restriction on updated classes, the method becomes dynamically type-safe. For instance, if no other classes depend on a field or method it may be removed. Similarly, changes to a class' type can be made as long as these changes do not cause type violations with the class' dependents. As their new dynamic class loader does not support transitive loading of classes causing type violations, their method is limited to dynamic update of a single class at a time, which is to restricting a change scope for any non-trivial software update. Furthermore, their method has to block all active threads, while updating a class in multithreaded applications, to prevent race conditions from happening. This blocking of threads causes undesirable bumps in the application execution when software updates take place.
In [7] Subramanian et al. disclose the method JVOLVE, that based on a modified Java Virtual machine, allows developers to add, delete, and replace fields and methods anywhere within the class hierarchy. JVOLVE implements these updates by adding to and coordinating VM class loading, just-in-time compilation, scheduling, return barriers, on-stack replacement, and garbage collection. To initialize new fields and update existing ones, JVOLVE applies class and object transformer functions, the former for static fields and the latter for object instance fields. Class and object transformer functions are prepared for each update by a so-called Update Preparation Tool, which examines differences between the former and the new versions of updated classes. JVOLVE stops the executing threads at VM safe points, where it is safe to perform garbage collection (GC) and thread scheduling. JVOLVE makes use of the garbage collector and JIT compiler to update the code and data associated with changed classes. JVOLVE initiates a whole-heap GC to find existing object instances of updated classes and initialize new versions using the provided object transformers. JVOLVE invalidates existing compiled code and installs new byte-code for all changed method implementations. When the application resumes execution these methods are JIT-compiled when they are next invoked. JVOLVE requires the software to reach a state of quiescence, i.e., all application threads must be stopped at a VM safe point, before an update can take place. The update process uses a stop-the-world garbage collection-based approach that requires the application to pause for the duration of a full heap garbage collection. This synchronized blocking of application threads at VM safe points causes service disruption for unpredictable periods of time.
In [8] Gustayson discloses the method JDrums, that extends a Java Virtual Machine with the ability to update classes while a program is running. To update classes with pre-existing instances in the running program JDrums converts all such objects into objects of the new class according to an update specification. Update specifications must be provided together with the class being updated when starting the update. Similarly it is possible to specify an update specification for static data in the updated classes. The update specifications are defined in Java source code in one so-called CONVERSION CLASS per updated class. The conversion class contains methods that define how the conversion is to be carried out. JDrums does not support dynamically changing the inheritance hierarchy of classes.
In [3] Orso et al. disclose the method DUSC (Dynamic Updating through Swapping of Classes), that based on a hot-swapping technique using indirection via object wrappers, allows the substitution, addition, and removal of classes from a running Java application. DUSC enables dynamic updating by first applying class renaming and code rewriting to introduce object wrappers, and then performing class update by swapping classes at runtime. The method imposed a number of restrictions on application programming: no class in the application is allowed to access public or protected fields of an updated class directly; reflection is not applied to any updated class or any component of an updated class (including any methods that inspect the information about a specific class, such as the methods in java.lang.Class, as a form of reflection as well); a new version of an updated class provides the same interface provided by the previous version of the class; updated classes may not contain native methods; no methods of updated classes are executing during an update (i.e., no methods of the class are on the stack.) Developers must take all of these restrictions into consideration when programming dynamically updatable applications using DUSC.
In [9] Bialek et al. disclose a method based on partitioning Java applications to make those partitions the updateable unit. The partitions of an application encapsulate the classes they contain and have explicitly provided and required interfaces, making them similar to components. The provided interface of the new partition's implementation must at least include the provided interfaces of the previous version, if not the update is rejected. Hence, the method does not support removal of public members from a provided interface. The information about the partitioning can be either provided by a developer or automatically extracted from source code. The disclosed method allows methods, fields and constructors to be added and method signatures to be changed by using version adapters. Each partition provides a state transfer function. The state transfer function for a partition includes mappings of states of an old partition's objects to their corresponding new versions. Application programmers are required to write these version adapters and state transfer functions. When a partition is updated all access to the partition is blocked. After the update has finished, the partition is unlocked and the application can continue its normal execution using the new versions of the updated partition's objects.
In [10] Hjalmtysson and Gray disclose the method, Dynamic C++ classes, that allows run-time updates of an executing C++ program at the class level. The method address the issue, that C++ does not directly support the creation of dynamically loadable modules, which makes preserving program-level abstractions across the dynamic-linking interface difficult. Dynamic C++ Classes is based on a proxy approach that exploits common C++ features and can be compiled with most modern compilers. The proxy approach supports version updates of existing classes as well as the introduction of new classes. To do so, the main program must be able to communicate with (invoke the methods of) the new implementation. Thus each implementation must have an interface that is known to the main program at compile time. Each new implementation either updates an existing class (a new version) or introduces a new class (a new type) that uses the known interface. Due to this restriction the method is restricted to update of methods only.
In [11] Stanek et al. disclose the method Dynamically Evolvable C++ Classes, that allows C++ classes to be dynamically updated. It includes the ability to add, remove, update, merge, and split classes. Dynamically merging and splitting of classes is enabled using state transformation functions. For an application to be used together with Dynamically Evolvable C++ Classes, some preparation of the application is needed. The preparation consists of: (a) writing the application using the smart pointer and container templates provided by the underlying framework of Dynamically Evolvable C++ Classes; (b) implementing for each class a common API defined by the framework; (c) implementing factory methods for instance creation and destruction; (d) compiling each class into a separate dynamically linked library; and (e) registering each of the dynamic class libraries with the class registry of the framework. The underlying framework is based on smart pointers, implemented as C++ templates, to keep track of object references after the state transformations of an update. As presented, the method only applies to single threaded applications, as safe state transformation under race conditions in multi-threaded applications are neglected.
In [12] Chen et al. disclose the method POLUS, that allows multithreaded software to be dynamically updated by running the old and new versions in parallel. POLUS achieves parallel execution by allowing simultaneously coexistence of both the old and the new versions of application data, and maintains the coherence between versions by calling some state synchronization functions whenever there is a write access to either version of the data to be updated. POLUS write-protects either version of the data during the updating process using the debugging APIs provided by operating systems (e.g. ptrace in Unix and DebugActiveProcess in Windows). This synchronization approach ensures consistency when several threads concurrently access different versions of data in multithreaded software. Parallel execution terminates as soon as there are no active threads in the old version. From there on, all function calls are redirected from the old version to the new version, using binary rewriting to insert an indirect jump instruction in the prologue of the original function. POLUS is design for dynamic update of imperative (procedural) programming languages, like the C programming language. POLUS is therefore not applicable to class-based object-oriented programming languages. U.S. Pat. No. 7,530,077 discloses a method and service for enabling a smallest unit of variable data within a data space of a user application to be dynamically updated using an external source. The application GUI is enhanced with a dynamic update utility (DUU) that enables the data unit to be selected and linked to the broker topic. Where the present invention addresses dynamic updating the programming code of actively running software, without losing the active state, the method of U.S. Pat. No. 7,530,077 addresses dynamic update of data values, a different problem.
U.S. Pat. No. 6,629,315 discloses a method, computer program product, and system for dynamically refreshing software modules within an actively running computer system. An existing module or multiple modules (recognizable units of executable code) are ready for execution in an active computer system. New modules corresponding in function to the existing modules are loaded into the computer system memory for updating the existing modules. The new modules are prepared for execution by pointing to corresponding state data currently being used by the existing modules and otherwise made ready to take over execution. A lock is held on execution exclusively by the refreshing process for a relatively brief moment in order to switch access from the call point or call references from the existing modules to the new modules. Releasing the lock allows execution of the new modules with the existing data thus accomplishing the update or refresh of the modules. Finally, the previous or “old” modules are removed from memory. Where the present invention enables non-blocking dynamic update of actively running software written in a statically-typed class-based object-oriented programming language, the method of U.S. Pat. No. 6,629,315 is restricted to blocking dynamic update of software written in a procedural language.
In view of the foregoing, there exists a need for a system, method and program product for transparent non-blocking dynamic updating of statically-typed class-based object-oriented software, without requiring the software or the computer running the software to be restarted, and without losing runtime state of the software as a consequence of performing an update on it.